/**
 * BPMN流程验证工具
 * 提供流程图的语法检查、业务逻辑验证和最佳实践建议
 */

export interface ValidationResult {
  isValid: boolean;
  errors: ValidationError[];
  warnings: ValidationWarning[];
  suggestions: ValidationSuggestion[];
}

export interface ValidationError {
  id: string;
  elementId?: string;
  elementType?: string;
  message: string;
  severity: 'error';
  category: 'syntax' | 'logic' | 'business';
}

export interface ValidationWarning {
  id: string;
  elementId?: string;
  elementType?: string;
  message: string;
  severity: 'warning';
  category: 'performance' | 'usability' | 'maintenance' | 'logic' | 'best-practice';
}

export interface ValidationSuggestion {
  id: string;
  elementId?: string;
  elementType?: string;
  message: string;
  severity: 'info';
  category: 'optimization' | 'best-practice' | 'performance';
}

export interface BpmnElement {
  id: string;
  type: string;
  name?: string;
  properties?: Record<string, any>;
  incoming?: string[];
  outgoing?: string[];
}

export interface BpmnProcess {
  id: string;
  name?: string;
  elements: BpmnElement[];
  sequenceFlows: BpmnSequenceFlow[];
}

export interface BpmnSequenceFlow {
  id: string;
  sourceRef: string;
  targetRef: string;
  conditionExpression?: string;
}

class BpmnValidator {
  private errors: ValidationError[] = [];
  private warnings: ValidationWarning[] = [];
  private suggestions: ValidationSuggestion[] = [];

  /**
   * 验证BPMN流程
   */
  validateProcess(process: BpmnProcess): ValidationResult {
    this.reset();

    // 基础语法验证
    this.validateSyntax(process);
    
    // 业务逻辑验证
    this.validateBusinessLogic(process);
    
    // 性能和可维护性检查
    this.validatePerformance(process);
    
    // 最佳实践建议
    this.validateBestPractices(process);

    return {
      isValid: this.errors.length === 0,
      errors: this.errors,
      warnings: this.warnings,
      suggestions: this.suggestions
    };
  }

  /**
   * 验证BPMN XML
   */
  validateXml(xml: string): ValidationResult {
    try {
      // 解析XML并转换为BpmnProcess对象
      const process = this.parseXmlToProcess(xml);
      return this.validateProcess(process);
    } catch (error) {
      this.addError('xml-parse-error', undefined, undefined, 
        `XML解析失败: ${error instanceof Error ? error.message : '未知错误'}`, 'syntax');
      
      return {
        isValid: false,
        errors: this.errors,
        warnings: this.warnings,
        suggestions: this.suggestions
      };
    }
  }

  private reset() {
    this.errors = [];
    this.warnings = [];
    this.suggestions = [];
  }

  private validateSyntax(process: BpmnProcess) {
    // 检查是否有开始事件
    const startEvents = process.elements.filter(el => el.type === 'bpmn:StartEvent');
    if (startEvents.length === 0) {
      this.addError('no-start-event', undefined, undefined, '流程必须包含至少一个开始事件', 'syntax');
    } else if (startEvents.length > 1) {
      this.addWarning('multiple-start-events', undefined, undefined, '流程包含多个开始事件，可能导致混淆', 'usability');
    }

    // 检查是否有结束事件
    const endEvents = process.elements.filter(el => el.type === 'bpmn:EndEvent');
    if (endEvents.length === 0) {
      this.addError('no-end-event', undefined, undefined, '流程必须包含至少一个结束事件', 'syntax');
    }

    // 检查元素连接性
    this.validateConnectivity(process);
    
    // 检查网关配置
    this.validateGateways(process);
    
    // 检查任务配置
    this.validateTasks(process);
  }

  private validateConnectivity(process: BpmnProcess) {
    process.elements.forEach(element => {
      // 检查孤立元素（除了开始和结束事件）
      if (element.type !== 'bpmn:StartEvent' && element.type !== 'bpmn:EndEvent') {
        const hasIncoming = element.incoming && element.incoming.length > 0;
        const hasOutgoing = element.outgoing && element.outgoing.length > 0;
        
        if (!hasIncoming && !hasOutgoing) {
          this.addError('isolated-element', element.id, element.type, 
            `元素 "${element.name || element.id}" 没有连接到任何其他元素`, 'logic');
        } else if (!hasIncoming) {
          this.addWarning('no-incoming-flow', element.id, element.type, 
            `元素 "${element.name || element.id}" 没有输入流`, 'logic');
        } else if (!hasOutgoing) {
          this.addWarning('no-outgoing-flow', element.id, element.type, 
            `元素 "${element.name || element.id}" 没有输出流`, 'logic');
        }
      }

      // 检查开始事件不应有输入流
      if (element.type === 'bpmn:StartEvent' && element.incoming && element.incoming.length > 0) {
        this.addError('start-event-incoming', element.id, element.type, 
          '开始事件不应该有输入流', 'syntax');
      }

      // 检查结束事件不应有输出流
      if (element.type === 'bpmn:EndEvent' && element.outgoing && element.outgoing.length > 0) {
        this.addError('end-event-outgoing', element.id, element.type, 
          '结束事件不应该有输出流', 'syntax');
      }
    });
  }

  private validateGateways(process: BpmnProcess) {
    const gateways = process.elements.filter(el => 
      el.type === 'bpmn:ExclusiveGateway' || 
      el.type === 'bpmn:ParallelGateway' || 
      el.type === 'bpmn:InclusiveGateway'
    );

    gateways.forEach(gateway => {
      // 检查网关是否有足够的输入/输出流
      const incomingCount = gateway.incoming?.length || 0;
      const outgoingCount = gateway.outgoing?.length || 0;

      if (gateway.type === 'bpmn:ExclusiveGateway') {
        if (outgoingCount < 2) {
          this.addWarning('gateway-insufficient-branches', gateway.id, gateway.type, 
            `排他网关 "${gateway.name || gateway.id}" 应该有至少2个输出分支`, 'logic');
        }
        
        // 检查条件表达式
        const outgoingFlows = process.sequenceFlows.filter(flow => flow.sourceRef === gateway.id);
        const hasDefaultFlow = outgoingFlows.some(flow => !flow.conditionExpression);
        const hasConditionFlows = outgoingFlows.some(flow => flow.conditionExpression);
        
        if (hasConditionFlows && !hasDefaultFlow) {
          this.addWarning('gateway-no-default', gateway.id, gateway.type, 
            `排他网关 "${gateway.name || gateway.id}" 建议设置默认流`, 'best-practice');
        }
      }

      if (gateway.type === 'bpmn:ParallelGateway') {
        if (incomingCount === 1 && outgoingCount < 2) {
          this.addWarning('parallel-gateway-split', gateway.id, gateway.type, 
            `并行网关 "${gateway.name || gateway.id}" 用于分支时应该有至少2个输出`, 'logic');
        }
        if (outgoingCount === 1 && incomingCount < 2) {
          this.addWarning('parallel-gateway-join', gateway.id, gateway.type, 
            `并行网关 "${gateway.name || gateway.id}" 用于合并时应该有至少2个输入`, 'logic');
        }
      }
    });
  }

  private validateTasks(process: BpmnProcess) {
    const tasks = process.elements.filter(el => 
      el.type === 'bpmn:UserTask' || 
      el.type === 'bpmn:ServiceTask' || 
      el.type === 'bpmn:ScriptTask' ||
      el.type === 'bpmn:Task'
    );

    tasks.forEach(task => {
      // 检查任务名称
      if (!task.name || task.name.trim() === '') {
        this.addWarning('task-no-name', task.id, task.type, 
          `任务 "${task.id}" 缺少名称`, 'usability');
      }

      // 检查用户任务的审批人配置
      if (task.type === 'bpmn:UserTask') {
        const assignee = task.properties?.assignee;
        const candidateGroups = task.properties?.candidateGroups;
        const candidateUsers = task.properties?.candidateUsers;
        
        if (!assignee && !candidateGroups && !candidateUsers) {
          this.addError('user-task-no-assignee', task.id, task.type, 
            `用户任务 "${task.name || task.id}" 必须配置审批人、候选组或候选用户`, 'business');
        }
        
        // 检查表单绑定
        const formKey = task.properties?.formKey;
        if (!formKey) {
          this.addSuggestion('user-task-no-form', task.id, task.type, 
            `用户任务 "${task.name || task.id}" 建议绑定表单`, 'best-practice');
        }
      }

      // 检查服务任务的实现
      if (task.type === 'bpmn:ServiceTask') {
        const implementation = task.properties?.implementation || task.properties?.class || task.properties?.delegateExpression;
        if (!implementation) {
          this.addError('service-task-no-implementation', task.id, task.type, 
            `服务任务 "${task.name || task.id}" 必须配置实现类或委托表达式`, 'business');
        }
      }
    });
  }

  private validateBusinessLogic(process: BpmnProcess) {
    // 检查流程复杂度
    this.validateComplexity(process);
    
    // 检查循环和死锁
    this.validateCycles(process);
    
    // 检查业务规则一致性
    this.validateBusinessRules(process);
  }

  private validateComplexity(process: BpmnProcess) {
    const elementCount = process.elements.length;
    const flowCount = process.sequenceFlows.length;
    
    if (elementCount > 50) {
      this.addWarning('high-complexity-elements', undefined, undefined, 
        `流程包含 ${elementCount} 个元素，建议拆分为子流程`, 'maintenance');
    }
    
    if (flowCount > 60) {
      this.addWarning('high-complexity-flows', undefined, undefined, 
        `流程包含 ${flowCount} 个连接线，可能过于复杂`, 'maintenance');
    }
    
    // 计算圈复杂度
    const cyclomaticComplexity = this.calculateCyclomaticComplexity(process);
    if (cyclomaticComplexity > 10) {
      this.addWarning('high-cyclomatic-complexity', undefined, undefined, 
        `流程圈复杂度为 ${cyclomaticComplexity}，建议简化流程逻辑`, 'maintenance');
    }
  }

  private validateCycles(process: BpmnProcess) {
    // 使用深度优先搜索检测循环
    const visited = new Set<string>();
    const recursionStack = new Set<string>();
    
    const hasCycle = (elementId: string): boolean => {
      if (recursionStack.has(elementId)) {
        return true;
      }
      if (visited.has(elementId)) {
        return false;
      }
      
      visited.add(elementId);
      recursionStack.add(elementId);
      
      const element = process.elements.find(el => el.id === elementId);
      if (element?.outgoing) {
        for (const outgoingId of element.outgoing) {
          const flow = process.sequenceFlows.find(f => f.id === outgoingId);
          if (flow && hasCycle(flow.targetRef)) {
            return true;
          }
        }
      }
      
      recursionStack.delete(elementId);
      return false;
    };
    
    const startEvents = process.elements.filter(el => el.type === 'bpmn:StartEvent');
    for (const startEvent of startEvents) {
      if (hasCycle(startEvent.id)) {
        this.addWarning('potential-infinite-loop', undefined, undefined, 
          '检测到潜在的无限循环，请检查流程逻辑', 'logic');
        break;
      }
    }
  }

  private validateBusinessRules(process: BpmnProcess) {
    // 检查审批层级合理性
    const userTasks = process.elements.filter(el => el.type === 'bpmn:UserTask');
    if (userTasks.length > 10) {
      this.addSuggestion('too-many-approvals', undefined, undefined, 
        `流程包含 ${userTasks.length} 个审批节点，建议优化审批层级`, 'optimization');
    }
    
    // 检查并行任务的合理性
    const parallelGateways = process.elements.filter(el => el.type === 'bpmn:ParallelGateway');
    if (parallelGateways.length > 5) {
      this.addSuggestion('too-many-parallel-branches', undefined, undefined, 
        '流程包含过多并行分支，可能影响性能', 'performance');
    }
  }

  private validatePerformance(process: BpmnProcess) {
    // 检查流程深度
    const maxDepth = this.calculateMaxDepth(process);
    if (maxDepth > 15) {
      this.addWarning('deep-process', undefined, undefined, 
        `流程深度为 ${maxDepth}，可能影响执行性能`, 'performance');
    }
    
    // 检查并发度
    const concurrentPaths = this.calculateConcurrentPaths(process);
    if (concurrentPaths > 8) {
      this.addWarning('high-concurrency', undefined, undefined, 
        `流程最大并发路径数为 ${concurrentPaths}，可能消耗过多资源`, 'performance');
    }
  }

  private validateBestPractices(process: BpmnProcess) {
    // 检查命名规范
    this.validateNamingConventions(process);
    
    // 检查文档完整性
    this.validateDocumentation(process);
    
    // 检查错误处理
    this.validateErrorHandling(process);
  }

  private validateNamingConventions(process: BpmnProcess) {
    process.elements.forEach(element => {
      if (element.name) {
        // 检查名称长度
        if (element.name.length > 50) {
          this.addSuggestion('long-element-name', element.id, element.type, 
            `元素名称过长: "${element.name}"`, 'best-practice');
        }
        
        // 检查特殊字符
        if (!/^[\u4e00-\u9fa5a-zA-Z0-9\s\-_()（）]+$/.test(element.name)) {
          this.addSuggestion('invalid-name-characters', element.id, element.type, 
            `元素名称包含特殊字符: "${element.name}"`, 'best-practice');
        }
      }
    });
  }

  private validateDocumentation(process: BpmnProcess) {
    if (!process.name || process.name.trim() === '') {
      this.addSuggestion('process-no-name', undefined, undefined, 
        '建议为流程设置名称', 'best-practice');
    }
    
    const undocumentedElements = process.elements.filter(el => 
      !el.name && el.type !== 'bpmn:SequenceFlow'
    );
    
    if (undocumentedElements.length > 0) {
      this.addSuggestion('undocumented-elements', undefined, undefined, 
        `有 ${undocumentedElements.length} 个元素缺少名称或描述`, 'best-practice');
    }
  }

  private validateErrorHandling(process: BpmnProcess) {
    const hasErrorEvents = process.elements.some(el => 
      el.type === 'bpmn:ErrorBoundaryEvent' || 
      el.type === 'bpmn:ErrorEndEvent'
    );
    
    const hasUserTasks = process.elements.some(el => el.type === 'bpmn:UserTask');
    const hasServiceTasks = process.elements.some(el => el.type === 'bpmn:ServiceTask');
    
    if ((hasUserTasks || hasServiceTasks) && !hasErrorEvents) {
      this.addSuggestion('no-error-handling', undefined, undefined, 
        '建议添加错误处理机制（错误边界事件或错误结束事件）', 'best-practice');
    }
  }

  private calculateCyclomaticComplexity(process: BpmnProcess): number {
    const edges = process.sequenceFlows.length;
    const nodes = process.elements.length;
    const components = 1; // 假设是连通图
    
    // 圈复杂度 = E - N + 2P (E=边数, N=节点数, P=连通分量数)
    return edges - nodes + 2 * components;
  }

  private calculateMaxDepth(process: BpmnProcess): number {
    const startEvents = process.elements.filter(el => el.type === 'bpmn:StartEvent');
    let maxDepth = 0;
    
    const calculateDepth = (elementId: string, currentDepth: number, visited: Set<string>): number => {
      if (visited.has(elementId)) {
        return currentDepth;
      }
      
      visited.add(elementId);
      const element = process.elements.find(el => el.id === elementId);
      
      if (!element?.outgoing || element.outgoing.length === 0) {
        return currentDepth;
      }
      
      let depth = currentDepth;
      for (const outgoingId of element.outgoing) {
        const flow = process.sequenceFlows.find(f => f.id === outgoingId);
        if (flow) {
          const childDepth = calculateDepth(flow.targetRef, currentDepth + 1, new Set(visited));
          depth = Math.max(depth, childDepth);
        }
      }
      
      return depth;
    };
    
    for (const startEvent of startEvents) {
      const depth = calculateDepth(startEvent.id, 0, new Set());
      maxDepth = Math.max(maxDepth, depth);
    }
    
    return maxDepth;
  }

  private calculateConcurrentPaths(process: BpmnProcess): number {
    // 简化实现：计算并行网关的最大分支数
    const parallelGateways = process.elements.filter(el => el.type === 'bpmn:ParallelGateway');
    let maxConcurrency = 1;
    
    for (const gateway of parallelGateways) {
      const outgoingCount = gateway.outgoing?.length || 0;
      if (outgoingCount > 1) {
        maxConcurrency = Math.max(maxConcurrency, outgoingCount);
      }
    }
    
    return maxConcurrency;
  }

  private parseXmlToProcess(xml: string): BpmnProcess {
    // 简化的XML解析实现
    // 实际项目中应该使用专业的BPMN解析库
    
    // 这里返回一个模拟的流程对象
    return {
      id: 'process_1',
      name: '示例流程',
      elements: [
        {
          id: 'start_1',
          type: 'bpmn:StartEvent',
          name: '开始',
          outgoing: ['flow_1']
        },
        {
          id: 'task_1',
          type: 'bpmn:UserTask',
          name: '审批任务',
          incoming: ['flow_1'],
          outgoing: ['flow_2']
        },
        {
          id: 'end_1',
          type: 'bpmn:EndEvent',
          name: '结束',
          incoming: ['flow_2']
        }
      ],
      sequenceFlows: [
        {
          id: 'flow_1',
          sourceRef: 'start_1',
          targetRef: 'task_1'
        },
        {
          id: 'flow_2',
          sourceRef: 'task_1',
          targetRef: 'end_1'
        }
      ]
    };
  }

  private addError(id: string, elementId: string | undefined, elementType: string | undefined, 
                  message: string, category: ValidationError['category']) {
    this.errors.push({ id, elementId, elementType, message, severity: 'error', category });
  }

  private addWarning(id: string, elementId: string | undefined, elementType: string | undefined, 
                    message: string, category: ValidationWarning['category']) {
    this.warnings.push({ id, elementId, elementType, message, severity: 'warning', category });
  }

  private addSuggestion(id: string, elementId: string | undefined, elementType: string | undefined, 
                       message: string, category: ValidationSuggestion['category']) {
    this.suggestions.push({ id, elementId, elementType, message, severity: 'info', category });
  }
}

// 导出单例实例
export const bpmnValidator = new BpmnValidator();

// 导出便捷方法
export const validateBpmnXml = (xml: string): ValidationResult => {
  return bpmnValidator.validateXml(xml);
};

export const validateBpmnProcess = (process: BpmnProcess): ValidationResult => {
  return bpmnValidator.validateProcess(process);
};